package models.accounts;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;

import javax.persistence.Entity;
import javax.persistence.Table;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import framework.base.BaseModel;
import framework.utils.ArrayUtil;
import framework.utils.DateUtil;
import framework.utils.StringUtil;
import models.resource.TrunkNo;
import models.security.User;
import play.Logger;
import play.data.validation.Check;
import play.data.validation.CheckWith;
import play.data.validation.Match;
import play.data.validation.MaxSize;
import play.data.validation.Required;
import play.libs.WS;
import play.libs.WS.HttpResponse;

@Entity
@Table(name="T_ACCOUNT")
public class Account extends BaseModel {
    //主账户ID
    public String sid;
    //主账户token
    public String token;
    //所属平台
    @Required(message="所属平台不能为空")
    public String platformType;
    //应用ID
    public String appId;
    //别名，域名
    @Required(message="域名不能为空")
   // @Match(value = "[0-9a-zA-Z]+",message="域名不合法")
    @Match(value="^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\\.[a-zA-Z][-a-zA-Z]{0,62})+$",message="域名不合法(例:example.yunkefu.com)")
    @CheckWith(value=AliasNameUniqueCheck.class,message="域名已存在")
    @MaxSize(value=32,message="域名不能超过32个字符")
    public String aliasName;
    //应用名称
    @Required(message="应用名不能为空")
    @CheckWith(value=AppNameUniqueCheck.class,message="应用名已存在")
    @MaxSize(value=10,message="名称不能超过10个字符")
    public String appName;
    //白名单
    public String whiteList;
    //回调地址
    public String notifyUrl;
    //业务类型
    public String bizType;
    //状态
    public String state;
    //开通时间
    public String dredgeAt;
    
    
    public Account(){
        this.status = USE_STATUS;
        this.createdAt = new Date();
        this.updatedAt = new Date();
        this.sid = AccountConstant.getAccountSid();
        this.token = AccountConstant.getAccountToken();
        this.notifyUrl = AccountConstant.getNotifyProxy();
        this.state =  STATE_READY_DREDGE;
    }
    

    
   private final static String STATE_READY_DREDGE="readyDredge";
   private final static String STATE_DREDGE="dredge";
   private final static String STATE_READY_SYNC="readySync";
   private final static String STATE_ERROR="error";
    
   
   static class AliasNameUniqueCheck extends Check{
       @Override
       public boolean isSatisfied(Object account, Object value) {
           boolean rcode = false;
           Account  _account = null;
           if(account instanceof Account){
               _account = (Account) account;
           }
           if(null!=_account){
               Account obj = Account.findByAliasName(StringUtil.trim(value));
               if(null==obj || obj.id.equals(_account.id)){
                   rcode = true;
               }
           }
           return rcode;
       }
   }
    
   static class AppNameUniqueCheck extends Check{
       @Override
       public boolean isSatisfied(Object account, Object value) {
           boolean rcode = false;
           Account  _account = null;
           if(account instanceof Account){
               _account = (Account) account;
           }
           if(null!=_account){
               Account obj = Account.findByAppName(StringUtil.trim(value));
               if(null==obj || obj.id.equals(_account.id)){
                   rcode = true;
               }
           }
           return rcode;
       }
   }
   
   public static Account findByAliasName(String aliasName){
       String sql="from Account a where a.aliasName=? and a.status=?";
       return Account.find(sql, aliasName,USE_STATUS).first();
   }
   
   public static Account findByAppName(String appName){
       String sql="from Account a where a.appName= ? and a.status=?";
       return Account.find(sql, appName,USE_STATUS).first();
   }
    
    /**
     * 获取所有未分配的中继号码
     * @return
     */
    public static Map<String,String> readyAssignTrunkNos(){
        return TrunkNo.queryAllReadyAssgin();
    }
    
    
    public List<TrunkNo> getTrunkNos(){
        return TrunkNo.queryByAccountId(this.id);
    }
    
   
    public void bind(String[] trunkNos){
        if(!ArrayUtil.isEmpty(trunkNos)){
            TrunkNo trunk = null;
            for(String s: trunkNos){
                trunk = TrunkNo.findById(s);
                if(null!=trunk){
                    trunk.bind(this.id);
                }
            }
        }
    }
    
    
    public void unbind(){
        List<TrunkNo> trunkNos = getTrunkNos();
        for(TrunkNo trunk : trunkNos){
            trunk.unbind();
        }
    }
    
    public void rebind(String[] trunkNos){
        unbind();
        bind(trunkNos);
    }
    
    public String listTrunkNos(){
        List<TrunkNo> trunkNos = getTrunkNos();
        StringBuffer sb = new StringBuffer();
        for(TrunkNo no : trunkNos){
            if(!StringUtil.isBlank(sb.toString())){
               sb.append(",");
            }
            sb.append(no.trunkNo);
        }
        return sb.toString();
    }
    
    /**
     * 创建账户
     */
    public Map<String,String> createAccount(){
        String url = AccountConstant.getAccountCreateUrl();
        Map<String,String> results = new HashMap<String,String>();
        try {
            results = notifyProxy(url);
            String rcode = results.get("rcode");
            if("true".equalsIgnoreCase(rcode)){
                this.state = STATE_DREDGE;
                this.appId = results.get("appId");
                this.dredgeAt = DateUtil.dateFormat(new Date(), DateUtil.FORMAT_TYPE_ALL);
                this.save();
            }else{
                this.state = STATE_ERROR;
                this.save();
            }
            Logger.info("[%s]: url<%s>, params<%s>, results<%s>", "createAccount",url,this.toParameters(),results);
        } catch (InterruptedException | ExecutionException e) {
            Logger.error(e, "Create Account [%s] Failed! -> params [%s]", this.id,this.toParameters());
        }   
        return results;
    }
    
    /**
     * 更新账户
     */
    public Map<String,String> updateAccount(){
        String url = AccountConstant.getAccountUpdateUrl();
        Map<String,String> results = new HashMap<String,String>();
        try {
            results = notifyProxy(url);
            String rcode = results.get("rcode");
            if(!"true".equalsIgnoreCase(rcode)){
                this.state = STATE_ERROR;
                this.save();
            }else{
                this.state = STATE_DREDGE;
                this.save();
            }
            Logger.info("[%s]: url<%s>, params<%s>, results<%s>", "updateAccount",url,this.toParameters(),results);
        } catch (InterruptedException | ExecutionException e) {
            Logger.error(e, "Update Account [%s] Failed! -> params [%s]", this.id,this.toParameters());
        } 
        return results;
    }
    
    /**
     * 删除账户
     */
    public Map<String,String> destroyAccount(){
        String url = AccountConstant.getAccountDestroyUrl();
        Map<String,String> results = new HashMap<String,String>();
        try {
            results = notifyProxy(url);
            String rcode = results.get("rcode");
            if(!"true".equalsIgnoreCase(rcode)){
                this.state = STATE_ERROR;
                this.save();
            }else{
                this.state = STATE_DREDGE;
                this.save();
            }
            Logger.info("[%s]: url<%s>, params<%s>, results<%s>", "destroyAccount",url,this.toParameters(),results);
        } catch (InterruptedException | ExecutionException e) {
            Logger.error(e, "Destroy Account [%s] Failed! -> params [%s]", this.id,this.toParameters());
        }        
        return results;
    }
    
    /**
     * 与代理平台进行交互
     * @param url
     * @return
     * @throws InterruptedException
     * @throws ExecutionException
     */
    public Map<String,String> notifyProxy(String url) throws InterruptedException, ExecutionException{
        Map<String,String> _params = this.toParameters();
        Map<String,String> results = new HashMap<String,String>();
        HttpResponse resp =  WS.url(url).setParameters(_params).postAsync().get();
        JsonElement _element = resp.getJson();
        if(_element.isJsonObject()){
            JsonObject obj = _element.getAsJsonObject();
            results = parseResult(obj);
        }
       return results;
    }
    
    /**
     * 解析回传结果
     * @param obj
     * @return
     */
    public Map<String,String> parseResult(JsonObject obj){
        Map<String,String> result = new HashMap<String,String>();
        String rcode = obj.get("rcode").getAsString();
        String id=obj.get("id").getAsString();
        String appId = obj.get("appId").getAsString();
        String msg = obj.get("msg").getAsString();
        result.put("rcode", rcode);
        result.put("id", id);
        result.put("appId", appId);
        result.put("msg", msg);
        return result;
        
    }
    
    /**
     * 生成接口传递参数
     * @return
     */
    public Map<String,String> toParameters(){
        Map<String,String> _params = new HashMap<String,String>();
        _params.put("id", this.id);
        _params.put("name", StringUtil.trim(this.appName));
//        _params.put("sid",  this.sid);
//        _params.put("token", this.token);
        _params.put("appId", this.appId);
        _params.put("trunkNos", this.listTrunkNos());
        _params.put("notifyUrl", this.notifyUrl);
        return _params;
    }
    
    
}
